<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>插槽</title>
    <script src="../vue.js"></script>
  </head>
  <body>
    <!-- 1 插槽内容 -->
    <div id="app1" style="border: 1px dashed blue;margin-bottom: 2px;">
    	<cmt1 :url="url">
        <!-- 插槽内可以包含任何模板代码，包括 HTML：（添加一个 Font Awesome 图标） -->
        <span class="fa fa-user">图标</span><br />
        <!-- 甚至其它的组件：(添加一个图标的组件) -->
        <font-awesome-icon name="user">icon-component</font-awesome-icon>
        baidu
      </cmt1>&nbsp;&nbsp;&nbsp;&nbsp;
    </div>
    <!-- 2 编译作用域 -->
    <div id="app2" style="border: 1px dashed red;margin-bottom: 2px;">
    	<cmt1 url="/url">
        <!-- baidu {{url}} ，此处的url无法访问，报错：
          [Vue warn]: Property or method "url" is not defined on the instance but referenced during render. 
          Make sure that this property is reactive, either in the data option, or for class-based components, 
          by initializing the property.
          RCA: 因为其 (指该插槽的) 内容是 传递给 <navigation-link> 的而不是在 <navigation-link> 组件内部 定义的。 
           -->
      </cmt1>
    </div>
    <!-- 3 后备内容 -->
    <div id="app3" style="border: 1px dashed blue;margin-bottom: 2px;">
      <cmt3></cmt3>
      <cmt3>Save</cmt3>
    </div>
    <!-- 4 具名插槽 -->
    <div id="app4" style="border: 1px dashed darkorange;margin-bottom: 2px;">
      <cmt4>
        <template v-slot:header>
          <h3>Here might be a page title</h3>
        </template>
        <!-- 现在 <template> 元素中的所有内容都将会被传入相应的插槽。
          任何没有被包裹在带有 v-slot 的 <template> 中的内容都会被视为默认插槽的内容。
          然而，如果你希望更明确一些，仍然可以在一个 <template> 中包裹默认插槽的内容：
            <template v-slot:default>
              <p>A paragraph for the main content.</p>
              <p>And another one.</p>
            </template>
         -->
        <p> ---------------</p>
        <p>A paragraph for the main content.</p>
        <p>And another one.</p>
        <p>---------------</p>
        <template v-slot:footer>
          <p>Here's some contact info</p>
        </template>
        <!-- 注意 v-slot 只能添加在 <template> 上 (只有一种例外情况)，这一点和已经废弃的 slot attribute 不同。 -->
      </cmt4>
    </div>
    <!-- 5 作用域插槽 -->
    <div id="app5" style="border: 1px dashed blue;margin-bottom: 2px;">
      <cmt5 :user="{firstName: 'witt', lastName: 'zhang'}">
        <!-- 我们可能想换掉备用内容，用名而非姓来显示。如下。
        然而该代码不会正常工作，因为只有 <current-user> 组件可以访问到 user，而我们提供的内容是在父级渲染的。
        {{ user.firstName }} -->
      </cmt5>
    </div>
    <div id="app6" style="border: 1px dashed darkorange;margin-bottom: 2px;">
      <cmt6 :user="{firstName: 'witt', lastName: 'zhang'}">
        <!-- ":default" 可以省略 -->
        <template v-slot:default="slotProps">
          {{ slotProps.user.firstName }}
        </template>
      </cmt6>
    </div>
    <!-- 5.1 独占默认插槽的缩写语法 -->
    <!-- 在上述情况下，当被提供的内容只有默认插槽时，组件的标签才可以被当作插槽的模板来使用。这样我们就可以把 v-slot 直接用在组件上： -->
    <div id="app7" style="border: 1px dashed darkorange;margin-bottom: 2px;">
      <cmt6 :user="{firstName: 'witt', lastName: 'zhang'}" v-slot:default="slotProps234">
        {{ slotProps234.user.firstName }}
      </cmt6>
      <br />
      <!-- 这种写法还可以更简单。就像假定未指明的内容对应默认插槽一样，不带参数的 v-slot 被假定对应默认插槽： -->
      <cmt6 :user="{firstName: 'witt', lastName: 'zhang'}" v-slot="slotProps567">
        {{ slotProps567.user.firstName }}
      </cmt6>
      <!--
      注意默认插槽的缩写语法不能和具名插槽混用，因为它会导致作用域不明确：
      只要出现多个插槽，请始终为所有的插槽使用完整的基于 <template> 的语法！
       -->
    </div>
    
    <!-- 5.2 解构插槽 Prop -->
    <div id="app8" style="border: 1px dashed blue;margin-bottom: 2px;">
      <!-- 
      v-slot 的值实际上可以是任何能够作为函数定义中的参数的 JavaScript 表达式。
      所以在支持的环境下 (单文件组件或现代浏览器)，你也可以使用 ES2015 解构来传入具体的插槽 prop，如下： -->
      <cmt6 :user="{firstName: 'witt', lastName: 'zhang'}" v-slot="{ user }">
        {{ user.firstName }}
      </cmt6>
      <!-- 这样可以使模板更简洁，尤其是在该插槽提供了多个 prop 的时候。
      它同样开启了 prop 重命名等其它可能，例如将 user 重命名为 person： -->
      <br />
      <cmt6 :user="{firstName: 'witt', lastName: 'zhang'}" v-slot="{ user: person }">
        {{ person.firstName }}
      </cmt6>
      <br />
      <!-- 你甚至可以定义后备内容，用于插槽 prop 是 undefined 的情形： -->
      <cmt6 :user="{firstName: 'witt', lastName: 'zhang'}" v-slot="{ user2 = { firstName: 'Guest' } }">
        {{ user2.firstName }}
      </cmt6>
    </div>
    <!-- 6 动态插槽名 -->
    <div id="app9" style="border: 1px dashed red;margin-bottom: 2px;">
      <cmt4>
        <template v-slot:[dynamicslotname]>
          <h3>Here might be a page title</h3>
        </template>
      </cmt4>
    </div>
    <!-- 7 具名插槽的缩写 -->
    <div id="app10" style="border: 1px dashed darkorange;margin-bottom: 2px;">
      <cmt4>
        <template #header>
          <h3>Here might be a page title</h3>
        </template>
        <!-- 现在 <template> 元素中的所有内容都将会被传入相应的插槽。
          任何没有被包裹在带有 v-slot 的 <template> 中的内容都会被视为默认插槽的内容。
          然而，如果你希望更明确一些，仍然可以在一个 <template> 中包裹默认插槽的内容：
            <template v-slot:default>
              <p>A paragraph for the main content.</p>
              <p>And another one.</p>
            </template>
         -->
        <p> ---------------</p>
        <p>A paragraph for the main content.</p>
        <p>And another one.</p>
        <p>---------------</p>
        <template #footer>
          <p>Here's some contact info</p>
        </template>
        <!-- 注意 v-slot 只能添加在 <template> 上 (只有一种例外情况)，这一点和已经废弃的 slot attribute 不同。 -->
      </cmt4>
    </div>
    <!-- 8 其它示例 -->
    <div id="app11" style="border: 1px dashed red;margin-bottom: 2px;">
      <cmt7 :filtered-todos="todos"></cmt7>
    </div>
    <div id="app12" style="border: 1px dashed blue;margin-bottom: 2px;">
      <cmt7 :filtered-todos="todos">
        <template v-slot:todo="{todo}">
          <span v-if="todo.isComplete">√</span>
          <span v-else>&nbsp;&nbsp;</span>
          {{todo.text}}
        </template>
      </cmt7>
    </div>
    <!-- 9 废弃了的语法 -->
    <!-- 9.1 带有 slot attribute 的具名插槽 -->
    <!-- 9.2 带有 slot-scope attribute 的作用域插槽 -->
    <script type="text/javascript">
      // 1 插槽内容
      Vue.component('cmt1', {
        props: ['url'],
        template: `
          <a :href="url" class="nav-link">
            <slot></slot>
          </a>
        `
      })
      
      Vue.component('font-awesome-icon', {
        template: '<div><slot></slot><img src="../favicon.ico" style="zoom: 10%;"/></div>'
      })
      
      var vm1 = new Vue({
        el: '#app1',
        data: {
          // url: "https://www.baidu.com/"
          url: "#"
        }
      })
      // 2 编译作用域
      var vm2 = new Vue({
        el: '#app2',
        data: {
        }
      })
      // 3 后备内容
      Vue.component('cmt3', {
        template: `
          <button type="submit">
            <slot>Submit</slot>
          </button>
        `
      })
      
      new Vue({
        el: '#app3'
      })
      // 4 具名插槽
      Vue.component('cmt4', {
        template: `
          <div class="container">
            <header>
              <!-- 我们希望把页头放这里 -->
              <slot name="header"></slot>
            </header>
            <main>
              <!-- 我们希望把主要内容放这里 -->
              <!-- 一个不带 name 的 <slot> 出口会带有隐含的名字“default” -->
              <slot></slot>
            </main>
            <footer>
              <!-- 我们希望把页脚放这里 -->
              <slot name="footer"></slot>
            </footer>
          </div>
        `
      })
      new Vue({
        el: '#app4'
      })
      // 5 作用域插槽
      Vue.component('cmt5', {
        props: ['user'],
        template: `
          <span>
            <slot>
              {{ user.lastName }}
            </slot>
          </span>
        `
      })
      new Vue({
        el: '#app5'
      })
      Vue.component('cmt6', {
        props: ['user'],
        template: `
          <span>
            <slot :user="user">
              {{ user.lastName }}
            </slot>
          </span>
        `
      })
      new Vue({
        el: '#app6'
      })
      // 5.1 独占默认插槽的缩写语法
      new Vue({
        el: '#app7'
      })
      new Vue({
        el: '#app8'
      })
      // 5.2 解构插槽 Prop
      // 6 动态插槽名
      new Vue({
        el: '#app9',
        data: {
          dynamicslotname: 'header'
        }
      })
      // 7 具名插槽的缩写
      new Vue({
        el: '#app10'
      })
      // 8 其它示例
      Vue.component('cmt7', {
        props: ['filteredTodos'],
        template: `
           <!-- 我们为每个 todo 准备了一个插槽，将 todo 对象作为一个插槽的 prop 传入 -->
           <ul>
             <li v-for="todo in filteredTodos"
                v-bind:key="todo.id"
             >
               <slot name="todo" :todo="todo">
                 <!-- 后备内容 -->
                 {{todo.text}}
               </slot>
             </li>  
           </ul>
        `
      })
      new Vue({
        el: '#app11',
        data: {
          todos: [
            {id: 1, text: 'todo1'},
            {id: 2, text: 'todo2'},
            {id: 3, text: 'todo3'}
          ]
        }
      })
      new Vue({
        el: '#app12',
        data: {
          todos: [
            {id: 1, text: 'todo4', isComplete: true},
            {id: 2, text: 'todo5', isComplete: false},
            {id: 3, text: 'todo6', isComplete: true}
          ]
        }
      })
      // 9 废弃了的语法
      // 9.1 带有 slot attribute 的具名插槽
      // 9.2 带有 slot-scope attribute 的作用域插槽
    </script>
  </body>
</html>
